home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Best of MacTutor - S…e Code for Volumes 1 to 5
/
The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin
/
Source Code
/
#49 (Oct 89)
/
DMP Source
/
src
/
PDriver.c
< prev
Wrap
Text File
|
1989-01-02
|
14KB
|
479 lines
/*
* This is the driver. A description of the driver can be found
* in the Device Manager chapter of Inside Macintosh, and a
* description of THIS driver can be found in the Print Manager
* chapter.
*/
/*
* This file is part of the DMP-110 printer driver for the Macintosh
* series of computers.
*/
/*
* Earle R. Horton.
* Wednesday, November 30, 1988
* All rights reserved.
*/
#define DRIVER
#include <Windows.h>
#include <Events.h>
#include <Dialogs.h>
#include <Fonts.h>
#include <Memory.h>
#include <Resources.h>
#include <ToolUtils.h>
#include <Errors.h>
#include <Desk.h>
#include "dmp-110.h"
#include "compat.h"
#define __SEG__ Main
#define lPrEvtAll 0x00FFFFFD
#define lPrEvtTop 0x00FEFFFD
#define dNeedGoodBye 4
int checkabort();
/* Useful constants */
#define SERRESET 8
#define SERSHAKE 10
#define XONCR ((char)17)
#define XOFFCR ((char)19)
#define RESFILEID (-8192)
extern char AOutName[],BOutName[];
extern short BaudRates[];
extern char prlfstr[];
extern char prinitstr[];
extern char prtopstr[];
extern char preopstr[];
extern char prmargin[];
extern char prhireslf[];
OSErr openprinterfile(),SPOpen();
/*
* Driver close routine.
* Close serial port. Dispose of our storage.
* Better not close the serial driver if we
* are dealing with 64k ROMs.
*
* Called by device manager under UniFinder when application
* heap is reinitialized.
*/
OSErr myPrClose(p,d) /* Device Close Call */
PrParam *p; /* ==> parameter block */
DCtlPtr d; /* ==> device control entry */
{
return(noErr);
}
#include <strings.h>
/*
* Printer driver open routine. Open our printer resource file, get
* any information we have stored there, allocate a non-relocatable
* block of storage, set up a serial port for use. Check errors.
*/
OSErr myPrOpen(p,d)
PrParam *p; /* ==> parameter block */
DCtlPtr d; /* ==> device control entry */
{
extern short DriverEntry;
return (noErr);
}
OSErr myPrPrime(p,d) /* We don't do prime. It's for drivers which do */
/* read/write directly. */
PrParam *p; /* ==> parameter block */
DCtlPtr d; /* ==> device control entry */
{
return(noErr);
}
OSErr myPrControl(p,d) /* Control calls. Many defined, few implemented. */
PrParam *p; /* ==> parameter block */
DCtlPtr d; /* ==> device control entry */
{
Dstorage storage;
char *buf = nil;
SysEnvRec World;
OSErr error;
ProcPtr idle;
SysEnvirons(1,&World);
PrSetError(noErr);
memset(&storage,0,sizeof(Dstorage));
error = SPOpen(&storage,&World);
if(error != noErr) return noErr;
storage.iopb.ioParam.ioResult = noErr;
if(setjmp(storage.abortbuf) != 0){
PBClose(&storage.iopb);
if(p->csCode == iPrEvtCtl){
DisposPtr(buf);
}
return noErr;
}
/*
* Device Control Call. p->csCode gives opcode, and we switch on it
* to perform low-level Printing calls
*/
switch (p->csCode){
case iPrBitsCtl: /* Send a bitmap to the printer. */
break;
case iPrEvtCtl: /* Screen printing. (cmd-shift 4.)*/
if(*(short*)(&p->lParam1) == 1){ /* Top window. */
buf = NewPtr(2000L);
if(buf != nil){
dumptop(&storage,buf);
DisposPtr(buf);
}
}
else if(*(short*)(&p->lParam1) == 2){ /* Screen. */
buf = NewPtr(2000L);
if(buf != nil){
dumpscreen(&storage,buf);
DisposPtr(buf);
}
}
break;
default:
break;
}
PBClose(&storage.iopb);
return noErr;
}
/*
* Printer driver status call, used by the Font Manager to request
* a copy of the printer's font characterization table. Ignored
* like the control call.
*/
OSErr myPrStatus(p,d) /* Device Status Call */
PrParam *p; /* ==> parameter block */
DCtlPtr d; /* ==> device control entry */
{
return (noErr);
}
/*
* Open the serial driver and configure it. Quit if ioResult field
* of parameter block ever becomes other than noErr.
*/
OSErr SPOpen(s,World)
register DPstorage s;
SysEnvRec *World;
{
register ParmBlkPtr pb;
int serconfig;
Pfg settings;
Handle pfilename;
short pfile;
pfilename = GetResource('STR ',0xE000);
if(pfilename == nil){
return ResError();
}
HLock(pfilename);
pfile = OpenResFile(*pfilename);
if(pfile == -1){
return ResError();
}
DisposHandle(pfilename);
settings = (Pfg)(GetResource('HEXA',RESFILEID));
if(settings == nil){
return ResError();
}
LoadResource(settings);
HNoPurge(settings);
pb = &s->iopb;
switch (pport){ /* get the correct port */
case 0: /* modem port */
pb->ioParam.ioNamePtr = (StringPtr)AOutName;
break;
case 1: /* printer port */
default:
if(IsMPPOpen()){
(void)StopAlert(ATALKALERT,nil);
return portInUse;
}
pb->ioParam.ioNamePtr = (StringPtr)BOutName;
break;
}
PBOpen(pb,FALSE);
if (pb->ioParam.ioResult != noErr){
return(pb->ioParam.ioResult);
}
pb->ioParam.ioNamePtr = nil;
/*
* Set up the io parameter block for writing to the serial driver.
* a control call resets the baud rate
*/
((CntrlParam *)pb)->csCode = SERRESET;
serconfig = data8 + noParity + stop20;
serconfig += BaudRates[pbaud];
((CntrlParam*)pb)->csParam[0] = serconfig;
PBControl(pb,FALSE);
if (pb->ioParam.ioResult != noErr) return(pb->ioParam.ioResult);
#define shake ((SerShk *)&((CntrlParam*)pb)->csParam[0])
shake->errs = FALSE;
shake->evts = FALSE;
shake->fDTR = FALSE;
shake->fInX = FALSE;
if(XonXoff && (World->machineType >= envMachUnknown)){
shake->fXOn = TRUE;
shake->fCTS = FALSE;
shake->xOn = XONCR;
shake->xOff = XOFFCR;
}
else {
shake->fXOn = FALSE;
shake->fCTS = TRUE;
}
((CntrlParam *)pb)->csCode = SERSHAKE;
PBControl(pb,FALSE);
if (pb->ioParam.ioResult != noErr) return(pb->ioParam.ioResult);
pb->ioParam.ioPosMode = 0;
pb->ioParam.ioPosOffset = 0;
return(noErr);
}
printstring(s,string) /* Send a printer control string to the */
/* serial driver. */
register DPstorage s;
unsigned char *string;
{
s->iopb.ioParam.ioBuffer = (Ptr)(string+1);
s->iopb.ioParam.ioReqCount = (long)(string[0]);
asyncwrite(s,checkabort);
}
/*
* dumptop() - Called to dump the top window to the screen. Nothing if
* top window is a color window.
*
* Uses PtInRgn() to determine the extent of the window's structure region,
* so we can print the entire window frame. If you know of a better way,
* let me know. Question: What do we do if we get a round window?
*/
dumptop(s,obuf)
DPstorage s;
short *obuf;
{
EventRecord myevent;
GrafPtr tmpport,oldport;
int i,rows,width,first_row,last_row,left_offset;
Rect printrect;
GetPort(&oldport);
tmpport = (GrafPtr)FrontWindow();
SetPort(tmpport);
/*
* Expand portRect to Rect enclosing Window structure region.
*/
printrect = tmpport->portRect;
LocalToGlobal(&printrect);
LocalToGlobal(&printrect.bottom);
while(PtInRgn(*(Point*)(&printrect),((WindowPeek)tmpport)->strucRgn)){
printrect.left--;
}
printrect.left++;
while(PtInRgn(*(Point*)(&printrect),((WindowPeek)tmpport)->strucRgn)){
printrect.top--;
}
printrect.top++;
while(PtInRgn(*(Point*)(&printrect.bottom),((WindowPeek)tmpport)->strucRgn)){
printrect.bottom++;
}
printrect.bottom--;
while(PtInRgn(*(Point*)(&printrect.bottom),((WindowPeek)tmpport)->strucRgn)){
printrect.right++;
}
printrect.right--;
GlobalToLocal(&printrect);
GlobalToLocal(&printrect.bottom);
/*
* Calculate rows in BitMap which we need to print. Send sixteen at a
* time to the BitMap printing routine.
*/
first_row = printrect.top - tmpport->portBits.bounds.top;
last_row = printrect.bottom - tmpport->portBits.bounds.top;
left_offset = printrect.left - tmpport->portBits.bounds.left;
width = printrect.right - printrect.left;
for(i=first_row;i<=last_row;i+=16){
bitmap_to_hires(s,&tmpport->portBits,i,
obuf,width,left_offset,last_row-i+1);
}
SetPort(oldport);
}
/*
* dumpscreen() - Called to dump the screen to the printer. Dumps the
* WMgrPort instead. Funky stuff if screen is not in two-color mode.
*/
dumpscreen(s,obuf)
DPstorage s;
short *obuf;
{
GrafPtr tmpport;
int i,rows,width;
GetWMgrPort(&tmpport);
rows = tmpport->portBits.bounds.bottom - tmpport->portBits.bounds.top;
width = tmpport->portRect.right - tmpport->portRect.left - 1;
for(i=0;i<=rows;i+=16){
bitmap_to_hires(s,&tmpport->portBits,i,obuf,width,0,rows-i);
}
}
/*
* bitmap_to_hires()
* This function translates a QuickDraw BitMap to codes which may
* be sent to a Tandy DMP-110 dot-matrix printer in high-resolution
* graphics mode. Graphics codes for this printer in hi-res mode
* include all eight bit characters. There are two characters for each
* column of 16 dots on the paper. The top dot (1) corresponds to bit
* zero of the first byte sent. The bottom dot (16) corresponds to bit
* eight of the second byte. There are 960 columns, or 1920 bytes, of
* graphics data to be sent for one line of graphics output.
* Note that the ToolBox bit manipulation routines use lower-to-upper
* bit order.
*
* No smarts in this routine, the whole 1918 bytes are sent for each
* line.
*/
bitmap_to_hires(s,b,row,obuf,width,left_offset,nleft)
DPstorage s; /* Global driver storage. */
BitMap *b; /* BitMap to print. */
int row; /* Starting row on this pass. */
short *obuf; /* Serial port output buffer. */
int width; /* Print this many columns. */
int left_offset; /* Start this far from left of b->bounds.left. */
int nleft; /* Max number of rows to print. */
{
short *obytes,*inbytes;
int column,lastcol,nbits,dot;
for(dot=960;dot-- >0;){
obuf[dot] = 0;
}
obytes = obuf;
lastcol = (b->bounds.right > 959) ? 959 : b->bounds.right;
lastcol = (lastcol > width) ? width : lastcol;
inbytes = (short *)(b->baseAddr + b->rowBytes*row);
nbits = b->rowBytes*8;
/*
* Transform QuickDraw BitMap to Tandy DMP-110 high resolution graphics
* using ToolBox bit-manipulation routines. Sixteen rows of BitMap
* at column become two-byte printing code.
*/
for(column=left_offset;column<=lastcol+left_offset;column++){
for(dot=0;dot<8 && dot<nleft;dot++){
if(BitTst(inbytes,(long)(column+dot*nbits))){
BitSet(obytes,(long)(7-dot));
}
}
for(dot=8;dot<16 && dot < nleft;dot++){
if(BitTst(inbytes,(long)(column+dot*nbits))){
BitSet(obytes,(long)(23-dot));
}
}
obytes++;
}
output_hires_data(s,obuf,(long)(lastcol)-1); /* Send to printer. */
}
/*
* output_hires_data() - Send a stream of high resolution graphics data
* to the Tandy DMP-110. The codes for transferring the graphics, and
* for the high-resolution paper advance, are hard-coded into this
* routine. Skips blank graphics codes, and repositions the printer
* head. The overhead is 8 bytes for repositioning the head and restarting
* high resolution graphics. If there are four blank columns, then, we
* break even. If there are more, we win. If there are less than four
* blank columns, we lose.
*/
output_hires_data(s,buf,columns)
DPstorage s;
short *buf;
long columns;
{
short *p;
short pos,ncodes,start,max;
max = (columns > 959) ? 959 : columns;
for(pos=0,ncodes=0,p=buf,start=0;pos<=columns;pos++){
if(buf[pos] == 0){
if(ncodes != 0){
sendcodes(s,p,ncodes,start);
ncodes = 0;
}
}else{
if(ncodes == 0){
p = &buf[pos];
start = pos;
}
ncodes++;
}
}
if(ncodes != 0){
sendcodes(s,p,ncodes,start);
}
printstring(s,prhireslf);
}
sendcodes(s,buf,n,pos)
DPstorage s;
char *buf;
int n,pos;
{
unsigned char codes[10];
s->iopb.ioParam.ioBuffer = (Ptr)&codes[0];
codes[0] = 27;
codes[1] = 16;
codes[2] = (pos>>8)&3;
codes[3] = pos & 0xFF;
codes[4] = 27;
codes[5] = 73;
codes[6] = (n>>8)&3;
codes[7] = n&0xFF;
s->iopb.ioParam.ioReqCount = 8;
asyncwrite(s,checkabort); /* Send 8 bytes to printer. */
s->iopb.ioParam.ioBuffer = &buf[0];
s->iopb.ioParam.ioReqCount = 2*n;
asyncwrite(s,checkabort); /* Print the buffer. */
}
/*
* checkabort() - Returns TRUE if command-'.' detected. Otherwise,
* FALSE.
*/
checkabort()
{
EventRecord myevent;
if(WaitNextEvent(everyEvent,&myevent,0L/*WaitTime*/,0L)){
if(LoWord(myevent.message & charCodeMask) == '.' &&
(myevent.modifiers & cmdKey) ){
PrSetError(iIOAbortErr);
return TRUE;
}
}
return FALSE;
}
/*
* Routine to write asynchronously to the serial port, and run an
* idle procedure while we wait. The idle routine may call PrSetError(),
* so we check PrError() for abort each time. Kill pending serial port
* IO if abort detected.
*/
asyncwrite(s,idle)
DPstorage s;
ProcPtr idle;
{
IOParam *p = &(s->iopb.ioParam);
PBWrite(p,TRUE); /* Issue ASYNC write. */
do{
(*idle)(); /* Idle til done. */
if(PrError() != noErr){ /* Check for abort. */
if(p->ioResult > 0){ /* More chars? */
PBKillIO(p,FALSE); /* Stop output. */
}
longjmp(s->abortbuf,1); /* Get out. */
}
}while(p->ioResult > 0); /* Check for complete. */
}